/*
 * TMap Designer - A Thematic Map design software
 * Copyright (C) 2006 World Health Organization
 * http://www.who.int
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
package who.tmap.toolkit.shape.annotation.impl;

import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.font.GlyphVector;
import java.awt.font.TextLayout;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

import org.apache.log4j.Logger;

import who.tmap.bo.TextStyle;
import who.tmap.toolkit.shape.LabelShape;
import who.tmap.toolkit.shape.MapShape;
import who.tmap.toolkit.shape.PolygonShape;
import who.tmap.toolkit.shape.annotation.LabelsListShape;
import who.tmap.util.MiscHelper;

/**
 * Polygon label
 * @author stl
 *
 */
public class LabelShapeImpl extends TextShapeImpl implements LabelShape {

    private static Logger logger = Logger.getLogger(LabelShapeImpl.class); 	
	
	private MapShape mapShape;
	private boolean visible;
	private Point2D distancePt;
	private LabelsListShape labelsList;
	
	public LabelShapeImpl() {
		setType( LABEL );
		visible =true;
		
		setDistancePt( new Point2D.Double( 0, 0 ) );
		setPt( new Point2D.Double( 0, 0 ) );
	}
	
	private String cloneString( String str ) {
		return str != null ? new String( str ) : null;
	}
	
    public Object deepClone() throws CloneNotSupportedException {
    	LabelShapeImpl lsi =new LabelShapeImpl();
    	
    	lsi.setId( cloneString( getId() ) );
    	lsi.setType( getType() );
    	lsi.setLayer( cloneString( getLayer() ) );
    	lsi.select( isSelected() );
    	lsi.setSelectedHandleIndex( getSelectedHandleIndex() );
    	lsi.setColor( getColor() );
    	lsi.setFillColor( getFillColor() );
    	
    	lsi.bounds =bounds != null ? (Rectangle2D)bounds.clone() : null;
    	lsi.setZoomFactor( getZoomFactor() );
    	lsi.setMapFactor( getMapFactor() );
    	lsi.setEditMode( getEditMode() );
    	
    	lsi.pt =(Point2D)pt.clone();
    	lsi.width =width;
    	lsi.height =height;
    	lsi.fillPattern =fillPattern;
    	lsi.backgroundColor =backgroundColor;

    	// from BaseAnnotationGraphicShapeImpl, might get trouble later
    	//protected Shape shape;
    	
    	lsi.fontName =cloneString( fontName );
    	lsi.fontStyle =fontStyle;
    	lsi.fontSize =fontSize;
    	
    	lsi.setText( cloneString( getText() ) );
    	lsi.font =font;
    	lsi.textShapeFactor =textShapeFactor;
    	
    	lsi.setVisible( visible );
    	lsi.setDistancePt( (Point2D)distancePt.clone() );
    	lsi.setLabelsList( labelsList );
    	
    	return lsi;
    }

	public MapShape getMapShape() {
		return mapShape;
	}

	public void setMapShape(MapShape mapShape) {
		this.mapShape = mapShape;
	}	

	public Point2D getDistancePt() {
		return distancePt;
	}

	public void setDistancePt(Point2D distancePt) {
		this.distancePt = distancePt;
	}

	public boolean isVisible() {
		return visible;
	}

	public void setVisible(boolean visible) {
		this.visible = visible;
	}	
	
	public LabelsListShape getLabelsList() {
		return labelsList;
	}

	public void setLabelsList(LabelsListShape labelsList) {
		this.labelsList = labelsList;
	}

	public void applyStyle( TextStyle textStyle ) {
		setFontName( new String( textStyle.getFontName() ) );
		setFontSize( textStyle.getFontSize() );		
		setFontStyle( textStyle.getFontStyle() );
	}
	
	public void moveShape( Point2D anchor, Point2D movingAnchor ) {
	    double offsetX =movingAnchor.getX() - anchor.getX();
	    double offsetY =movingAnchor.getY() - anchor.getY();
	    
	    distancePt.setLocation( distancePt.getX() + offsetX, 
	    						distancePt.getY() + offsetY );	    
	}	
	
	/**
	 * Draw the text
	 */
	public void draw(Graphics g) {  
	    
		PolygonShape polygon =(PolygonShape)mapShape;
		
		if ( !MiscHelper.isMacOS() ) {
			TextLayout textLayout =getTextLayout( g, getText() );		
			
			Point2D centerPt =polygon.getCenter();
			pt.setLocation( centerPt.getX() + distancePt.getX() - (textLayout.getBounds().getWidth() / 2.d),
							centerPt.getY() + distancePt.getY() + ( textLayout.getBounds().getHeight() / 2.d ) );
				
			textLayout.draw( ((Graphics2D)g), (float)pt.getX(), (float)pt.getY() );		
			
			bounds =textLayout.getBounds();
		    bounds.setRect( bounds.getX() + pt.getX(),
	                  		bounds.getY() + pt.getY() ,
	                  		bounds.getWidth(),
	                  		bounds.getHeight() );	
		} else {
			Graphics2D g2 =(Graphics2D)g;
			Font savFont =g2.getFont();

			Font scaledFont =getScaledFont( g );
			g2.setFont( scaledFont );

			GlyphVector gv = scaledFont.createGlyphVector( g2.getFontRenderContext(), getText() );
			Rectangle2D strBounds =font.getStringBounds( getText(), g2.getFontRenderContext() );

			Point2D centerPt =polygon.getCenter();
			pt.setLocation( centerPt.getX() + distancePt.getX() - (strBounds.getWidth()*textShapeFactor / 2.d),
							centerPt.getY() + distancePt.getY() - (strBounds.getHeight()*textShapeFactor / 2.d) );
			
			bounds =new Rectangle2D.Double( pt.getX()  
			  		  					  , pt.getY() - ( strBounds.getHeight()*textShapeFactor )
			  		  					  , strBounds.getWidth()*textShapeFactor 
			  		  					  , strBounds.getHeight()*textShapeFactor );
			
			gv.performDefaultLayout();
			g2.drawGlyphVector(gv, (float)pt.getX(), (float)pt.getY() );
			
			g2.setFont( savFont );
		}
		
		displaySelectionHandles( g );

	}	
	
}
